package tunnel

import (
	"fmt"
	"log"
	"strconv"
	"time"

	"internal-net-bridge-server/internal/models"
	"internal-net-bridge-server/internal/utils"
)

// ========================================
// 隧道管理器核心CRUD方法
// ========================================
// 本文件包含从 manager.go.bak 提取的完整业务逻辑方法

// SyncTunnelID 同步隧道ID：当数据库ID与内存ID不一致时调用
// 这个方法会停止旧监听器，更新Tunnel对象，重启新监听器
func (tm *TunnelManager) SyncTunnelID(oldID, newID string) error {
	tm.mutex.Lock()
	defer tm.mutex.Unlock()

	log.Printf("🔄 [ID同步] 开始同步隧道ID:")
	log.Printf("   ├─ 旧ID: %s", oldID)
	log.Printf("   └─ 新ID: %s", newID)

	// 1. 检查旧隧道是否存在
	tunnel, exists := tm.tunnels[oldID]
	if !exists {
		return fmt.Errorf("旧隧道不存在: %s", oldID)
	}

	// 2. 停止旧ID的协议监听器
	tm.stopProtocolListener(oldID)
	log.Printf("✅ [ID同步] 已停止旧监听器: %s", oldID)

	// 3. 从tunnels map中删除旧key
	delete(tm.tunnels, oldID)

	// 4. 从portMappings中更新映射（如果存在）
	if tunnel.PublicPort != "" {
		if existingTunnel, exists := tm.portMappings[tunnel.PublicPort]; exists && existingTunnel.ID == oldID {
			tm.portMappings[tunnel.PublicPort] = tunnel
		}
	}

	// 5. 更新Tunnel对象的ID
	tunnel.ID = newID
	log.Printf("✅ [ID同步] 已更新Tunnel对象ID: %s", newID)

	// 6. 用新ID作为key保存Tunnel
	tm.tunnels[newID] = tunnel
	log.Printf("✅ [ID同步] 已保存到tunnels map: key=%s", newID)

	// 7. 重启协议监听器（使用新ID）
	if tm.protocolFactory != nil && tunnel.PublicPort != "" && tunnel.PublicPort != "0" {
		log.Printf("🔄 [ID同步] 重启监听器: 端口=%s, 新TunnelID=%s", tunnel.PublicPort, newID)
		go tm.startProtocolListener(tunnel)
	}

	log.Printf("✅ [ID同步] 隧道ID同步完成: %s -> %s", oldID, newID)
	return nil
}

// CreateTunnel 创建新隧道（完整实现）
func (tm *TunnelManager) CreateTunnel(req *models.TunnelRequest) (*models.TunnelResponse, error) {
	tm.mutex.Lock()
	defer tm.mutex.Unlock()

	// 根据ip+端口查询是否存在隧道
	existingTunnel := tm.findTunnelByLocalAddress(req.LocalHost, req.LocalPort)

	var tunnel *models.Tunnel
	var tunnelID string
	var tunnelPort string
	var publicPort string
	var canReusePort bool = false

	if existingTunnel != nil {
		// 如果存在隧道，重用隧道ID和端口
		log.Printf("🔄 发现现有隧道，重用隧道ID: %s", existingTunnel.ID)
		tunnelID = existingTunnel.ID
		tunnelPort = existingTunnel.TunnelPort
		oldPublicPort := existingTunnel.PublicPort

		// 检查是否可以复用公共端口
		if existingTunnel.PublicPort != "" {
			// 简化：直接复用端口
			canReusePort = true
			publicPort = existingTunnel.PublicPort
			log.Printf("🔄 端口复用检查: 端口 %s 可复用", publicPort)
		}

		if !canReusePort {
			// 重新分配公共端口
			newPublicPort, err := utils.GetAvailablePort()
			if err != nil {
				return nil, fmt.Errorf("无法分配公共端口: %v", err)
			}
			publicPort = newPublicPort

			// 🔧 停止旧的协议监听器
			if existingTunnel.PublicPort != "" {
				log.Printf("🛑 停止旧监听器: 隧道ID=%s, 端口=%s", existingTunnel.ID, existingTunnel.PublicPort)
				tm.stopProtocolListener(existingTunnel.ID)
				delete(tm.portMappings, existingTunnel.PublicPort)
			}
		} else {
			// ✅ 端口复用时，保持监听器运行，避免停止-重启导致端口冲突
			log.Printf("✅ 端口复用: 保持监听器运行，隧道ID=%s, 端口=%s", existingTunnel.ID, publicPort)
		}

		// 更新现有隧道
		existingTunnel.ServerName = req.ServerName
		existingTunnel.PublicPort = publicPort
		existingTunnel.ProtocolType = req.TunnelType // 🆕 更新协议类型
		existingTunnel.CreatedAt = time.Now()
		existingTunnel.IsConnected = false

		// 🆕 更新UserID（如果请求中提供了新的UserID）
		if req.UserID != "" {
			existingTunnel.UserID = req.UserID
		} else if existingTunnel.UserID == "" {
			// 如果现有隧道也没有UserID，使用TunnelID
			existingTunnel.UserID = existingTunnel.ID
		}

		tunnel = existingTunnel
		log.Printf("✅ 隧道更新完成:")
		log.Printf("   ├─ 隧道ID: %s (重用)", tunnelID)
		log.Printf("   ├─ 用户ID: %s", existingTunnel.UserID) // 🆕 打印UserID
		log.Printf("   ├─ 本地地址: %s:%s", req.LocalHost, req.LocalPort)
		if canReusePort {
			log.Printf("   ├─ 公共端口: %s (复用)", publicPort)
		} else {
			log.Printf("   ├─ 旧公共端口: %s (已释放)", oldPublicPort)
			log.Printf("   └─ 新公共端口: %s", publicPort)
		}
	} else {
		// 创建新隧道
		tunnelID = fmt.Sprintf("tunnel-%s-%s", req.LocalHost, req.LocalPort)

		// 分配隧道端口
		tm.tunnelPort++
		tunnelPort = strconv.Itoa(tm.tunnelPort)

		// 分配公共端口
		newPublicPort, err := utils.GetAvailablePort()
		if err != nil {
			return nil, fmt.Errorf("无法分配公共端口: %v", err)
		}
		publicPort = newPublicPort

		// 创建新隧道
		// 🆕 从请求中获取UserID，如果没有则使用TunnelID作为默认UserID
		userID := req.UserID
		if userID == "" {
			userID = tunnelID // 默认使用隧道ID作为用户ID
		}

		tunnel = &models.Tunnel{
			ID:           tunnelID,
			UserID:       userID,         // 🆕 设置用户ID（用于计费）
			ProtocolType: req.TunnelType, // 🆕 设置协议类型（http/tcp/udp）
			LocalHost:    req.LocalHost,
			LocalPort:    req.LocalPort,
			ServerName:   req.ServerName,
			TunnelHost:   "127.0.0.1",
			TunnelPort:   tunnelPort,
			PublicPort:   publicPort,
			CreatedAt:    time.Now(),
			RequestMap:   make(map[string]*models.HTTPRequest),
			IsConnected:  false,
		}

		log.Printf("🆕 创建新隧道:")
		log.Printf("   ├─ 隧道ID: %s", tunnelID)
		log.Printf("   ├─ 用户ID: %s", userID) // 🆕 打印UserID
		log.Printf("   ├─ 本地地址: %s:%s", req.LocalHost, req.LocalPort)
		log.Printf("   ├─ 隧道端口: %s", tunnelPort)
		log.Printf("   └─ 公共端口: %s", publicPort)
	}

	// 保存隧道到内存
	tm.tunnels[tunnelID] = tunnel
	tm.portMappings[publicPort] = tunnel

	// 🚀🚀🚀 使用协议工厂启动监听器（抽象接口架构）
	var listenerStartError error
	if publicPort != "" && publicPort != "0" {
		if tm.protocolFactory != nil {
			log.Printf("🚀 [CreateTunnel] 准备启动监听器: 隧道ID=%s, 协议=%s, 端口=%s",
				tunnelID, tunnel.ProtocolType, publicPort)

			// 🔧 同步启动监听器并检查结果
			listenerStartError = tm.startProtocolListenerSync(tunnel)
			if listenerStartError != nil {
				log.Printf("❌ [CreateTunnel] 监听器启动失败: %v", listenerStartError)
				// 不返回错误，允许隧道创建，但状态设置为error
			} else {
				log.Printf("✅ [CreateTunnel] 监听器启动成功")
			}
		} else {
			log.Printf("⚠️ [CreateTunnel] 协议工厂未初始化，跳过端口监听: 端口=%s", publicPort)
		}
	} else {
		log.Printf("⚠️ [CreateTunnel] 公共端口无效，跳过监听器: publicPort=%s", publicPort)
	}

	// 注册域名映射到DomainRouter（如果启用）
	// 注意：域名URL将由API层通过 CreateTunnelMapping 生成并持久化
	// 这里只是预留接口，实际域名注册在API层完成

	// 持久化到数据库
	// 注意：隧道创建由API层通过 CreateTunnelMapping 完成
	// 如果监听器启动失败，状态设置为 error；否则设置为 active
	if tm.tunnelService != nil {
		if listenerStartError != nil {
			// 监听器启动失败，设置状态为 error
			errorMsg := listenerStartError.Error()
			if err := tm.tunnelService.UpdateTunnelStatus(tunnelID, "error", &errorMsg); err != nil {
				log.Printf("⚠️ 更新隧道状态为error失败: %v", err)
			} else {
				log.Printf("⚠️ 隧道状态已更新为 error (监听器启动失败)")
			}
		} else {
			// 监听器启动成功，设置状态为 active
			if err := tm.tunnelService.UpdateTunnelStatus(tunnelID, "active", nil); err != nil {
				log.Printf("⚠️ 更新隧道状态失败: %v", err)
			} else {
				log.Printf("✅ 隧道状态已更新为 active")
			}
		}
	}

	// 构建响应
	response := &models.TunnelResponse{
		TunnelID:   tunnelID,
		TunnelHost: tunnel.TunnelHost,
		TunnelPort: tunnelPort,
		PublicPort: publicPort,
	}

	return response, nil
}

// DeleteTunnel 删除隧道
func (tm *TunnelManager) DeleteTunnel(tunnelID string) error {
	tm.mutex.Lock()
	defer tm.mutex.Unlock()

	tunnel, exists := tm.tunnels[tunnelID]
	if !exists {
		return fmt.Errorf("隧道不存在: %s", tunnelID)
	}

	// 🚀 停止协议监听器（抽象接口架构）
	tm.stopProtocolListener(tunnelID)

	// 关闭连接（向后兼容）
	if tunnel.TunnelConn != nil {
		tunnel.TunnelConn.Close()
	}

	// 关闭公共端口监听（向后兼容）
	if tunnel.PublicListener != nil {
		tunnel.PublicListener.Close()
	}

	// 清理映射
	delete(tm.tunnels, tunnelID)
	if tunnel.PublicPort != "" {
		delete(tm.portMappings, tunnel.PublicPort)
	}
	if tunnel.Domain != "" {
		delete(tm.domainMappings, tunnel.Domain)
	}

	// 从数据库删除
	if tm.tunnelService != nil {
		// 简化：跳过数据库删除，由API层处理
		log.Printf("ℹ️  跳过数据库删除，由API层处理")
	}

	log.Printf("✅ 隧道已删除: %s", tunnelID)
	return nil
}

// findTunnelByLocalAddress 根据本地地址查找隧道
func (tm *TunnelManager) findTunnelByLocalAddress(localHost, localPort string) *models.Tunnel {
	// 1. 首先查询数据库
	if tm.tunnelService != nil {
		localPortInt, err := strconv.ParseInt(localPort, 10, 64)
		if err != nil {
			log.Printf("❌ 解析本地端口失败: %s, 错误: %v", localPort, err)
			return nil
		}

		tunnelMapping, err := tm.tunnelService.GetTunnelMappingByLocalAddress(localHost, localPortInt)
		if err != nil {
			log.Printf("❌ 查询数据库隧道映射失败: %v", err)
			return nil
		}

		if tunnelMapping != nil {
			log.Printf("🔍 数据库中找到匹配的隧道映射:")
			log.Printf("   ├─ 隧道ID: %s", tunnelMapping.TunnelID)
			log.Printf("   ├─ 本地地址: %s:%d", tunnelMapping.LocalIP, tunnelMapping.LocalPort)
			log.Printf("   └─ 公共端口: %d", tunnelMapping.PublicPort)

			// 2. 检查内存中是否已有对应的隧道对象（用数据库ID查找）
			if existingTunnel, exists := tm.tunnels[tunnelMapping.TunnelID]; exists {
				log.Printf("✅ 内存中找到对应的隧道对象（TunnelID=%s）", tunnelMapping.TunnelID[:8]+"...")
				return existingTunnel
			}

			// 🔥 3. 检查是否存在使用不同ID的隧道（通过LocalHost+LocalPort查找）
			// 这种情况发生在：内存中的隧道ID与数据库ID不一致
			for oldID, existingTunnel := range tm.tunnels {
				if existingTunnel.LocalHost == tunnelMapping.LocalIP &&
					existingTunnel.LocalPort == strconv.FormatInt(tunnelMapping.LocalPort, 10) {
					log.Printf("⚠️  发现ID不一致的隧道:")
					log.Printf("   ├─ 数据库ID: %s", tunnelMapping.TunnelID[:8]+"...")
					log.Printf("   ├─ 内存ID: %s", oldID[:8]+"...")
					log.Printf("   └─ 🔄 更新隧道ID为数据库ID")

					// 🔥 停止旧ID的协议监听器
					tm.stopProtocolListener(oldID)

					// 删除旧Key
					delete(tm.tunnels, oldID)

					// 更新隧道ID
					existingTunnel.ID = tunnelMapping.TunnelID

					// 用新Key保存
					tm.tunnels[tunnelMapping.TunnelID] = existingTunnel

					// 🔥 重启协议监听器（使用新ID）
					if tm.protocolFactory != nil && existingTunnel.PublicPort != "" {
						log.Printf("🔄 重启监听器: 端口=%s, 新TunnelID=%s", existingTunnel.PublicPort, tunnelMapping.TunnelID[:8]+"...")
						go tm.startProtocolListener(existingTunnel)
					}

					log.Printf("✅ 隧道ID已同步并重启监听器: %s -> %s", oldID[:8]+"...", tunnelMapping.TunnelID[:8]+"...")
					return existingTunnel
				}
			}

			// 4. 根据数据库信息重建隧道对象
			log.Printf("🔄 根据数据库信息重建隧道对象")
			tunnel := &models.Tunnel{
				ID:          tunnelMapping.TunnelID,
				LocalHost:   tunnelMapping.LocalIP,
				LocalPort:   strconv.FormatInt(tunnelMapping.LocalPort, 10),
				ServerName:  tunnelMapping.ServiceName,
				TunnelHost:  "127.0.0.1",
				TunnelPort:  "9001", // 与客户端配置匹配
				PublicPort:  strconv.FormatInt(tunnelMapping.PublicPort, 10),
				CreatedAt:   time.Now(), // 使用当前时间
				RequestMap:  make(map[string]*models.HTTPRequest),
				IsConnected: false,
			}
			return tunnel
		}
	}

	// 2. 如果数据库查不到，遍历内存中的隧道
	for _, tunnel := range tm.tunnels {
		if tunnel.LocalHost == localHost && tunnel.LocalPort == localPort {
			log.Printf("🔍 在内存中找到匹配的隧道: %s", tunnel.ID)
			return tunnel
		}
	}

	log.Printf("ℹ️  未找到匹配的隧道: %s:%s", localHost, localPort)
	return nil
}
